//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<IObject.h>
///	@path  ~/src/object/
///	@date	2007/06/12
///	@desc	IObject base interface.

#pragma once

#include "xeres.h"

#include "lib/utilities/string.h"

#include "object/object_ref.h"
#include "object/object_factory.h"

namespace xeres {

	// forward declaration
	class Time;

	/*! 
		\ingroup iobject_module

		\class	IObject
		\brief	Object interface base.
		\details
			IObject runtime system is the base of xeres,
			nearly all xeres elements are derived from IObject.<BR>
			On of the core design concept of xeres is : <b>everything is an IObject instance</b>.<BR>
			<BR>
			To use an instance of any IObject class, A Ref object should be use instead of raw pointer.
			Ref encapsulates smart pointer feature of IObject, it auto increases or decreases reference
			count. Users can control instance reference manually, but it's not recommended.<BR>
			See Ref for more information.<BR>
			<BR>
			To define a new interface, first you should use \ref DECL_IOBJECT_INTERFACE to declare
			IObject features in class declarations. And use \ref IMPL_IOBJECT_INTERFACE in compilation unit
			to complete IObject feature implementations.<BR>
			<BR>
			To define a new class, just like interface, \ref DECL_IOBJECT_CLASS should appear in declaration,
			and \ref IMPL_IOBJECT_CLASS should be defined in compilation unit.<BR>
			<BR>
			There's a special type of class which can be created dynamically by passing class name or
			class id to ObjectFactory. To define a dynamic class, use \ref DECL_IOBJECT_CLASS_DYNAMIC in
			declaration, and \ref IMPL_IOBJECT_CLASS_DYNAMIC in compilation.<BR>

		\sa	Ref,ObjectFactory

		\eg	Demonstrates how to define a new interface.

		\code
			// in <INewInterface.h>
			class INewInterface : public IObject
			{
			public:
				INewInterface( void );
				DECL_IOBJECT_INTERFACE( INewInterface , IObject )
			};

			// in <INewInterface.cpp>
			IMPL_IOBJECT_INTERFACE( INewInterface );
			INewInterface::INewInterface( void )
			{
			}
			// ... and so on

		\endcode

		\eg Implementing class & dynamic class is similar to interface.
	
		\code
			// in <CNewClass.h>
			class CNewClass : public INewInterface
			{
			public:
				INewInterface( void );
				DECL_IOBJECT_CLASS( CNewClass , INewInterface )
			};

			// in <CNewClass.cpp>
			IMPL_IOBJECT_CLASS( CNewClass );
			CNewClass::CNewClass( void )
			{
			}
			// ... and so on

		\endcode

	*/
	class IObject
	{
	public:

		/// \name Constructor & Destructor
		//@{

		/// \ctor
		IObject( void );

		/// \dtor
		virtual ~IObject( void );

		//@}

		/// \name RTTI Interface
		//@{

		/*!
			\brief		Get class name of this object.
			\details	Get class name of this object. For RTTI.
						This function <b>must</b> be overrided to indicate different
						classes using by the system. Usually the function should be implemented
						by \ref IMPL_IOBJECT_CLASS or \ref IMPL_IOBJECT_CLASS_DYNAMIC macro,
						it's not recommended to implement manually.
			\return		Class name of this class.
		*/
		virtual const WString& GetClassName( void ) const = 0;

		/*!
			\brief		Get ancient class name of this object.
			\details	Get ancient(super) class name of this object. For RTTI.
						Use this function to get some class compatible information.
						But don't implement compatible check depend on this function.
						<b>Any class compatibility feature should be queried by 'IsA'.</b><BR>
						Similar to \ref GetClassName, this function should be implemented by
						\ref IMPL_IOBJECT_CLASS or \ref IMPL_IOBJECT_CLASS_DYNAMIC macro.
			\return		Ancient class name of this class.
		*/
		virtual const WString& GetAncientName( void ) const = 0;

		/*!
			\brief		Get class ID of this object.
			\details	Every registered class has a unique ID to identify itself
						inside RTTI system. Though class name is a way of identification,
						ID is more efficient and stable way of compatibility check.<BR>
						<I>It's recommended to let system process all Class ID information,
						user should not use Class ID for any extra process.</I>
			\return		Class ID of this class.
		*/
		virtual const ClassID GetClassID( void ) const = 0;

		/*!
			\brief		Get ancient class ID of this object.
			\details	It's not recommended to get ancient class ID. This function is
						designed for internal RTTI system, but must be overridden to
						produce new class.
			\return		Ancient class ID of this class.
		*/
		virtual const ClassID GetAncientID( void ) const = 0;

		/*!
			\brief		Get compatibility of specific class.
			\details	Core RTTI function. All classes can perform dynamic cast,
						from child to parent and from parent to child. While casting
						a parent class to child, RTTI will check compatibility of
						parent-child relationship.
			\return		Result of " this is a 'className' " class.
			\param[in]	className	Class name of destination class.

			\sa			ObjectFactory::IsCompatible
		*/
		bool IsA( const WString& className ) const;

		/*!
			\brief		Get compatibility of specific class.
			\details	Almost the same as 'IsA' string version. An ID is a little faster
						than string.
			\return		Result of " this is a 'classId' " class.
			\param[in]	classId		Class ID of destination class.

			\sa			ObjectFactory::IsCompatible
		*/
		bool IsA( const ClassID classId ) const;

		/*!
			\brief		Get compatibility of specific class.
			\details	For fast static detection, introducing template ways of detect.
						Specialize ancient class could make a little faster while performing static cast.
						Finally, if static type cast cannot resolve compatibility, dynamic method
						will be called.
						<I> This mechanism greatly reduce runtime cost of dynamic type cast. </I>
			\return		Result of " this is a 'classId' " class.

			\sa			ObjectFactory::IsCompatible
		*/
		template<
			typename _OtherIObject
		> __forceinline bool IsA( void ) const { return IsA( _OtherIObject::StaticClassID() ); }
		//@}

		/// \name Attribute Flags
		//@{
		/*!
			\brief		Get specific flags.
			\details	Get specific flags from object attribute bits.
			\return		Bit of flags combination.
		*/
		uint32 GetFlags( uint32 mask ) const { return m_attrFlags & mask; }

		/*!
			\brief		Get all flags.
			\details	Get all flags from object attribute bits.
			\return		Bits of flags combination.
		*/
		uint32 GetFlags( void ) const { return m_attrFlags; }

		/*!
			\brief		Set specific flags.
			\details	Set specific flags of object attribute. Notice this method only sets bits after 4 bit of flag.
						The first 4 bits are reserved.
		*/
		void SetFlags( uint32 mask );

		/*!
			\brief		Clear specific flags.
			\details	Clear specific flags of object attribute. Notice this method only sets bits after 4 bit of flag.
						The first 4 bits are reserved.
		*/
		void ClearFlags( uint32 mask );

		/*!
			\brief		Set specific flags with synchronization.
			\details	Set specific flags of object attribute. Notice this method only sets bits after 4 bit of flag.
						The first 4 bits are reserved.
			\return		The flag bits before set.
		*/
		uint32 SetFlagsAsync( uint32 mask );

		/*!
			\brief		Clear specific flags with synchronization.
			\details	Clear specific flags of object attribute. Notice this method only sets bits after 4 bit of flag.
						The first 4 bits are reserved.
			\return		The flag bits before set.
		*/
		uint32 ClearFlagsAsync( uint32 mask );

	protected:

		/*!
			\brief		Set base flag.
			\details	Sets the base 4 bits flags by children.
		*/
		void SetBaseFlags( uint32 mask );

		/*!
			\brief		Clear base flag.
			\details	Clear the base 4 bits flags by children.
		*/
		void ClearBaseFlags( uint32 mask );

		/*! 
			\var		s_nextAvaildBit
			\brief		Next available bit of flag.
		*/
		static const uint32 s_nextAvaildBit = 4;
		static const uint32 s_maxAvaildBit = 31;

		//@}

	public:

		/// \name Reference Counted Management
		//@{
		/*!
			\brief		Add reference count of object.
			\details	Increase reference count(with interlocked).
		*/
		void AddRef( void );

		/*!
			\brief		Release reference count of object.
			\details	Decrease reference count(with interlocked).
			\remarks	This function will delete object itself if count is zero.
		*/
		void ReleaseRef( void );

		/*!
			\brief		Add reference count of object without locking.
			\details	Increase reference count(without interlocked).
		*/
		void AddRefUnsafe( void );

		/*!
			\brief		Release reference count of object without locking.
			\details	Decrease reference count(without interlocked).
			\remarks	This function will delete object itself if count is zero.
		*/
		void ReleaseRefUnsafe( void );

		/*! 
			\brief		Return reference count of current object.
		*/
		int GetRefCount( void ) const;

		/*!
			\brief		Return if currently object has only 1 reference.
			\details	In some case we need to let the holder determine if currently
						only itself holds a single reference of the object. Holder will
						release unique reference in this situation. This function use for
						determine object is referenced only one holder.
			\return		True if only one holder references object, false if more references exist.
		*/
		bool IsUniqueRef( void ) const;

		/*!
			\brief		Called when add reference.
			\details	A function for engine debug, overload this function to debug abnormal
						reference count, shows how counter's increased and decreased.
			\param[in]	refCount	Reference count of object before increase ref.
		*/
		virtual void OnAddRef( int refCount );

		/*!
			\brief		Called when release reference.
			\details	A function for engine debug, overload this function to debug abnormal
						reference count, shows how counter's increased and decreased.
			\param[in]	refCount	Reference count of object before decrease ref.
		*/
		virtual void OnReleaseRef( int refCount );

		//@}


		/// \name	Inheritance Supports
		//@{

		/*!
			\brief		Get class name statically.
			\details	This function is actually used for storing class name.
						Function should be generated by
						\ref IMPL_IOBJECT_INTERFACE, \ref IMPL_IOBJECT_CLASS or \ref IMPL_IOBJECT_CLASS_DYNAMIC.
			\return		Class name.
		*/
		static const WString& StaticClassName( void );

		/*!
			\brief		Get class ID statically.
			\details	This function is actually used for storing Class ID.
						Function should be generated by
						\ref IMPL_IOBJECT_INTERFACE, \ref IMPL_IOBJECT_CLASS or \ref IMPL_IOBJECT_CLASS_DYNAMIC.
			\return		Class ID.
		*/
		static const ClassID StaticClassID( void );

		//@}

	protected:

		/// \name	Class Registration & Object Allocation
		//@{

		/*!
			\brief		Allocate new space for object
			\details	Internal method to allocate memory space for new object construction.
						Allocation finally goes to ObjectFactory's internal implementation.
						<b>Overloading new operator to implement customized allocation is
						not safe and not recommended.</b>
			\return		New space address for object.
			\param[in]	size	Allocate size.
			\param[in]	id		Class id.
		*/
		static void * AllocateObject( size_t size , const ClassID id );

		/*!
			\brief		Deallocate object instance space.
			\details	Internal method to deallocate memory space of deleted object.
						Similar to \ref AllocateObject, this function finally goes to
						\ref ObjectFactory 's internal implementation.
						<b>Overloading delete operator to implement customized destruction is
						not safe and not recommended.</b>
			\param[in,out]	ptr		Object address.
			\param[in]		id		Class id.
		*/
		static void DeallocateObject( void * ptr , const ClassID id );

	private:

		/*!
			\brief		This function is called by internal helper class.
						In IObject, this function is used for verify class registration.
			\details	Expose interface to out most compilation unit, can cause a automatic registration
						of class. This function do not register class, it's called by a internal
						registration helper class. Actual registration is done by StaticClassID which
						generated by \ref IMPL_IOBJECT_CLASS or \ref IMPL_IOBJECT_CLASS_DYNAMIC.
			\remarks	To register a class manually, use \ref IOBJECT_REGISTER_CLASS instead.
			\param[in]	name			Class name.
			\param[in]	idFunction		A function which returns class ID.
										Usually points to staticClassId() function.
		*/
		static void RegisterThisClass( const WString& name , const ClassID (*idFunction)( void ) );

		//@}

#ifndef _DOC_GEN
	public:
		// Helper for registering class.
		template< typename _IObjectClass > class ObjectClassHelper
		{
		public:
			/// \ctor
			ObjectClassHelper( void )
			{
				do {
					IObject::RegisterThisClass( _IObjectClass::StaticClassName() , _IObjectClass::StaticClassID );
				} while(0);
			}
		};
#endif/*_DOC_GEN*/

	private:

#ifndef _DOC_GEN
		// A padding member for 32bit vptr.
		// This variable only valid on 32bit system.
		// It's a place holder for 16 byte alignment & for 64bit pointer padding.
		PAD64(vptr);
#endif/*_DOC_GEN*/

		/*!
			\var		m_refCount
			\brief		Reference counter.
		*/
		volatile int	m_refCount;

		/*!
			\var		m_attrFlags
			\brief		Attribute flags.
		*/
		volatile int	m_attrFlags;


		/// For validating reference count.
		friend class ObjectFactory;

		/// For reference ownership helper.
		friend class ObjectOwnershipHelper;

	}; // class IObject

	/// Declare inheritance relationship
#define	DECL_IOBJECT_INHERITANCE( CLASS , ANCIENT ) \
	private: \
		typedef ANCIENT _AncientClassOf##CLASS##;\
		typedef ANCIENT _AncientType;

	/// Specialize static IsA determination.
#define	DECL_OBJECT_COMPATIBLE( CLASS ) \
	public:	\
		__forceinline bool IsA( const WString& className ) const { return IObject::IsA( className ); } \
		__forceinline bool IsA( const ClassID classId ) const { return IObject::IsA( classId ); } \
		template< typename _OtherIObject > __forceinline bool IsA( void ) const { \
			return _AncientClassOf##CLASS##::IsA<_OtherIObject>(); } \
		template<> __forceinline bool IsA< CLASS >( void ) const { return true; } \
		template<> __forceinline bool IsA< _AncientClassOf##CLASS## >( void ) const { return true; }

	/// \def DECL_IOBJECT_INTERFACE(CLASS,ANCIENT)
	/// Interface derived from IObject must use this macro to complete declaration.
#define DECL_IOBJECT_INTERFACE( CLASS , ANCIENT ) \
		DECL_IOBJECT_INHERITANCE( CLASS , ANCIENT ) \
	public: \
		DECL_OBJECT_COMPATIBLE( CLASS ) \
		virtual const WString& GetClassName( void ) const; \
		virtual const WString& GetAncientName( void ) const; \
		virtual const ClassID GetClassID( void ) const; \
		virtual const ClassID GetAncientID( void ) const; \
		template< typename _IObjectClass > friend class Ref; \
		friend class IObject::ObjectClassHelper< CLASS >; \
		static const WString& StaticClassName( void ); \
		static const ClassID StaticClassID( void )

	/// \def DECL_IOBJECT_CLASS(CLASS,ANCIENT)
	/// Class derived from IObject must use this macro to complete declaration.
	/// This macro declares class has no dynamic constructor.
#define	DECL_IOBJECT_CLASS( CLASS , ANCIENT ) \
		DECL_IOBJECT_INTERFACE( CLASS , ANCIENT ); \
	private: \
		IObject::ObjectClassHelper< CLASS > __reg##CLASS##Class; \
	public: \
		void * operator new( size_t size ); \
		void operator delete( void * ); \

	/// \def DECL_IOBJECT_CLASS_DYNAMIC(CLASS,ANCIENT)
	/// Class derived from IObject must use this macro to complete declaration.
	/// This macro indicates class can be constructed dynamically.
#define	DECL_IOBJECT_CLASS_DYNAMIC( CLASS , ANCIENT ) \
		DECL_IOBJECT_INTERFACE( CLASS , ANCIENT ); \
	private: \
		static IObject * ConstructObject( void * ); \
		IObject::ObjectClassHelper< CLASS > __reg##CLASS##Class; \
	public: \
		void * operator new( size_t size ); \
		void operator delete( void * ); \

	// Implement IObject.
#define	IMPL_IOBJECT_BASE( CLASS ) \
	\
	const WString& CLASS::GetClassName( void ) const { \
		return StaticClassName(); \
	} \
	const WString& CLASS::GetAncientName( void ) const { \
		return _AncientClassOf##CLASS##::StaticClassName(); \
	} \
	const ClassID CLASS::GetClassID( void ) const { \
		return StaticClassID(); \
	} \
	const ClassID CLASS::GetAncientID( void ) const { \
		return _AncientClassOf##CLASS##::StaticClassID(); \
	} \
	const WString& CLASS::StaticClassName( void ) { \
		static const WString __##CLASS##ClassName( _WIDE_STR(#CLASS) ); \
		return __##CLASS##ClassName; \
	}

	/// \def IMPL_IOBJECT_INTERFACE(CLASS)
	/// Interface derived from IObject must use this macro to complete declaration.
#define IMPL_IOBJECT_INTERFACE( CLASS ) \
	IMPL_IOBJECT_BASE( CLASS ) \
	const ClassID CLASS::StaticClassID( void ) { \
		static ClassID __##CLASS##ClassID = INVALID_CLASS_ID; \
		if( __##CLASS##ClassID == INVALID_CLASS_ID ) \
			__##CLASS##ClassID = ObjectFactory::RegisterInterface( \
				CLASS::StaticClassName() , _AncientClassOf##CLASS##::StaticClassID() ); \
		return __##CLASS##ClassID; \
	}

	/// Class derived from IObject must use this macro to complete implementation.
#define IMPL_IOBJECT_CLASS_BASE( CLASS ) \
	IMPL_IOBJECT_BASE( CLASS ) \
	const ClassID CLASS::StaticClassID( void ) { \
		static ClassID __##CLASS##ClassID = ObjectFactory::RegisterClass( \
			CLASS::StaticClassName() , _AncientClassOf##CLASS##::StaticClassID() , CLASS::ConstructObject , sizeof(CLASS) ); \
		return __##CLASS##ClassID; \
	} \
	IObject::ObjectClassHelper<CLASS> __##CLASS##_static_initor; \
	void * CLASS::operator new( size_t size ) { \
		return IObject::AllocateObject( size , StaticClassID() ); \
	} \
	void CLASS::operator delete( void * ptr ) { \
		IObject::DeallocateObject( ptr , StaticClassID() ); \
	}\

	/// \def IMPL_IOBJECT_CLASS(CLASS)
	/// Class derived from IObject must use this macro to complete implementation.
#define IMPL_IOBJECT_CLASS( CLASS ) \
	IMPL_IOBJECT_BASE( CLASS ) \
	const ClassID CLASS::StaticClassID( void ) { \
		static ClassID __##CLASS##ClassID = ObjectFactory::RegisterClass( \
			CLASS::StaticClassName() , _AncientClassOf##CLASS##::StaticClassID() , NULL , sizeof(CLASS) ); \
		return __##CLASS##ClassID; \
	} \
	IObject::ObjectClassHelper<CLASS> __##CLASS##_static_initor; \
	void * CLASS::operator new( size_t size ) { \
		return IObject::AllocateObject( size , StaticClassID() ); \
	} \
	void CLASS::operator delete( void * ptr ) { \
		IObject::DeallocateObject( ptr , StaticClassID() ); \
	}\

	/// Defines a simple object constructor.
#define	DEFAULT_IOBJECT_CONSTRUCTOR( CLASS ) \
	IObject * CLASS::ConstructObject( void * ptr ) { \
		return ::new ( ptr ) CLASS; \
	}

	/// \def IMPL_IOBJECT_CLASS_DYNAMIC(CLASS)
	/// Class derived from IObject must use this macro to complete implementation.
	/// This macro used to implement dynamic created IObject classes.
#define	IMPL_IOBJECT_CLASS_DYNAMIC( CLASS ) \
	IMPL_IOBJECT_CLASS_BASE( CLASS ); \
	DEFAULT_IOBJECT_CONSTRUCTOR( CLASS )

	/// \def IOBJECT_REGISTER_CLASS(CLASS)
	/// Use this macro to manually register class.
#define	IOBJECT_REGISTER_CLASS( CLASS ) \
	do{ \
		IObject::ObjectClassHelper< CLASS > __register##CLASS##; \
	} while(0);

	/// \def DECL_IOBJECT_CLASS_FLAG(NAME,POSITION)
	/// Use this macro to declare flags of object attributes.
#define DECL_IOBJECT_CLASS_FLAG( NAME , POSITION ) \
	static const uint32 s_flagBits_##NAME## = ( 1 << ( _AncientType::s_nextAvaildBit + POSITION ) ); \
	inline void Set##NAME##Flag( bool value ) { if( value ) SetFlags( s_flagBits_##NAME## ); else ClearFlags( s_flagBits_##NAME## ); } \
	inline void Set##NAME##Flag( void ) { SetFlags( s_flagBits_##NAME## ); } \
	inline void Reset##NAME##Flag( void ) { ClearFlags( s_flagBits_##NAME## ); } \
	inline bool Get##NAME##Flag( void ) const { return GetFlags( s_flagBits_##NAME## ) != 0; }

	/// \def DECL_IOBJECT_CLASS_FLAG_COUNT(COUNT)
	/// Use this macro to declare flags count.
#define DECL_IBOEJCT_CLASS_FLAG_COUNT( COUNT ) \
protected: \
	static const uint32 s_nextAvaildBit = _AncientType::s_nextAvaildBit + COUNT;

} // namespace xeres
